package com.xlh.controller.courseTest;

import com.xlh.aop.PreAcquireLock;
import com.xlh.common.Result;
import com.xlh.constant.ReportConstant;
import com.xlh.dto.PageDTO;
import com.xlh.dto.course.ClassZtreeDTO;
import com.xlh.dto.courseTest.AnswerSheetListDTO;
import com.xlh.dto.courseTest.AnswerSheetTypeDTO;
import com.xlh.dto.courseTest.PaperReadingDTO;
import com.xlh.dto.courseTest.TypeReadingDTO;
import com.xlh.dto.courseTest.check.ExperimentReportDTO;
import com.xlh.dto.courseTest.model.ModelNotChapterDTO;
import com.xlh.dto.courseTest.paper.PaperDTO;
import com.xlh.dto.courseTest.paper.PaperDetailDTO;
import com.xlh.dto.courseTest.paper.TeacherPaperDTO;
import com.xlh.param.courseTest.*;
import com.xlh.pojo.courseTest.CourseTestPaper;
import com.xlh.pojo.courseTest.CourseTestPaperModel;
import com.xlh.pojo.user.Class;
import com.xlh.security.UserInfoHolder;
import com.xlh.service.courseTest.*;
import com.xlh.util.BeanUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author zhr 2019/1/30 考试模块试卷生成Controller层，包括试题模板的相关接口
 * 1. 获取当前教师的所有试题模板
 * 2. 添加试题模板
 * 3. 删除试题模板
 * 4. 预览试题（根据传参的不同分为随机，全选择）
 * 5. 保存试卷
 * 6. 展示当前教师所有试卷和学生考试列表(与6合一起)
 * 7. 删除试卷
 * 8. 选择班级开始考试：选择开始考试后，需要根据考试时长算出考试结束时间，并需要一个延时通信，考试时间结束后，用户需要强制交卷；
 * 交卷后，使用异步自动批阅选择题和判断题；前端每次点击新题时，都提交一次答题情况
 * 9. 批卷（参考学生列表）：展示所有的参考学生名单，点击学生进入批卷细节
 * 10.批卷（学生答题详情）：展示选择题、判断题批阅情况，以及所有试题的原题，学生答案，标准答案等信息。
 * 11.批卷（提交批阅结果）
 * 12.根据模板类型返回题型、题型中文说明、该题型的试题数list
 * 13.获取考试题及考试剩余时间，业务中需要删除答案信息（学生端）
 * 14.获取考试题（教师端）
 * 15.上传答题情况
 * 16.保存答题情况
 */
@RestController
@Api(tags = "PaperController", description = "试卷接口")
@RequestMapping("/course/{courseId}/course-test")
public class PaperController {

    @Autowired
    private PaperService paperService;
    @Autowired
    private PaperModelService paperModelService;
    @Autowired
    private QuestionRepositoryService questionRepositoryService;
    @Autowired
    private ClassListService classListService;
    @Autowired
    private ExperimentService experimentService;
    @Autowired
    private PaperAnswerSheetService answerSheetService;

    @Autowired
    private UserInfoHolder userInfoHolder;

    @ApiOperation("模板：获取当前教师的所有试题模板")
    @GetMapping("/paper-model")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<CourseTestPaperModel>> getPaperModel(
            @RequestParam(value = "isChapterModel", required = false) Boolean isChapterModel,
            @PathVariable("courseId") Long courseId) {
        List<CourseTestPaperModel> list = paperModelService.getPaperModel(
                isChapterModel, courseId
        );

        return Result.success(list);
    }

    @ApiOperation("模板：添加试题模板")
    @PostMapping("/paper-model")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result addPaperModel(
            @RequestBody @Valid PaperModelInsertParam paperModelInsertParam,
            @PathVariable("courseId") Long courseId) {
        paperModelService.addPaperModel(paperModelInsertParam, courseId);

        return Result.success();
    }

    @ApiOperation("模板：删除试题模板")
    @DeleteMapping("/paper-model/{modelId}")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result deletePaperModel(@PathVariable("modelId") Long modelId, @PathVariable Long courseId) {
        paperModelService.deletePaperModel(modelId, courseId);

        return Result.success();
    }

    @ApiOperation("模板：试题模板详情")
    @GetMapping("/paper-model/{modelId}")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<CourseTestPaperModel> paperModelDetails(@PathVariable("modelId") Long modelId) {
        return Result.success(paperModelService.selectByPrimaryKey(modelId));
    }

    @ApiOperation("试卷生成：查看题目数量")
    @GetMapping("/question-count")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<ModelNotChapterDTO>> questionCount(
            @PathVariable("courseId") Long courseId, @RequestParam(value = "chapterId", required = false) Long chapterId) {
        return Result.success(questionRepositoryService.questionCount(courseId, chapterId));
    }

    @ApiOperation("试卷生成：教师学生试卷列表")
    @GetMapping("/paper")
    @PreAuthorize("@permissionValidator.isTeacherOrStudent()")
    public Result listPaper(
            @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
            @PathVariable("courseId") Long courseId) {
        if (userInfoHolder.isTeacher()) {
            return Result.success(paperService.listPaper(pageNum, pageSize, courseId));
        } else {
            return Result.success(paperService.listPaper(userInfoHolder.getUserId(), courseId));
        }
    }

    @ApiOperation("试卷生成：预览试卷")
    @PostMapping("/paper/preview")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<TeacherPaperDTO> previewPaper(
            @PathVariable("courseId") Long courseId, @RequestBody @Valid PreviewPaperParam param) {
        TeacherPaperDTO teacherPaperDTO = paperService.previewPaper(courseId, param);

        return Result.success(teacherPaperDTO);
    }

    @ApiOperation("试卷生成：预览页面保存试卷")
    @PostMapping("/paper")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result savePaper(@PathVariable("courseId") Long courseId, @RequestBody @Valid PaperParam param) {
        paperService.savePaper(courseId, param);
        return Result.success();
    }

    @ApiOperation("试卷生成：非预览页面保存试卷")
    @PostMapping("/paper/no-preview")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result savePaperWithoutPreview(@PathVariable("courseId") Long courseId, @RequestBody @Valid PreviewPaperParam param) {
        // 走一遍预览的逻辑再保存试卷
        PaperParam paperParam = BeanUtil.transform(
                PaperParam.class, paperService.previewPaper(courseId, param)
        );
        paperService.savePaper(courseId, paperParam);
        return Result.success();
    }

    @ApiOperation("试卷详情：返回试卷详细信息")
    @GetMapping("/paper/detail")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result paperDetail(Long paperId) {
        // 走一遍预览的逻辑再保存试卷
        PaperDetailDTO paperDetailDTO = paperService.paperDetail(paperId);
        return Result.success(paperDetailDTO);
    }

    @ApiOperation("试卷生成：删除试卷")
    @DeleteMapping("/paper/{paperId}")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result deletePaper(@PathVariable("paperId") Long paperId, @PathVariable Long courseId) {
        paperService.deletePaper(paperId, courseId);

        return Result.success();
    }

    @ApiOperation("考试：开始考试")
    @PostMapping("/paper/{paperId}/test")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result startTest(
            @PathVariable("courseId") Long courseId,
            @PathVariable("paperId") Long paperId, @RequestBody @Valid TestStartParam param) {

        paperService.startTest(courseId, paperId, param);
        return Result.success();
    }

    @ApiOperation("考试：获取试题")
    @GetMapping("/paper/{paperId}/paper")
    @PreAuthorize("@permissionValidator.isTeacherOrStudent()")
    public Result<PaperDTO> paperDetails(
            @PathVariable("paperId") Long paperId,
            @PathVariable("courseId") Long courseId,
            @RequestParam(value = "questionId", required = false) Long questionId) {
        return Result.success(
                paperService.paperDetails(userInfoHolder.isTeacher(), userInfoHolder.getUserId(), paperId, questionId, courseId)
        );
    }

    @ApiOperation("考试：查询默认班级")
    @GetMapping("/paper/default-class")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<Class> getDefaultClass(@PathVariable("courseId") Long courseId) {
        return Result.success(paperService.getDefaultClass(courseId));
    }

    @ApiOperation("考试：查询未结课授课班级")
    @GetMapping("/paper/class-list")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<List<ClassZtreeDTO>> getClassList(@PathVariable("courseId") Long courseId) {
        return Result.success(classListService.getClassList(courseId));
    }

    @ApiOperation("考试：保存学生答题情况")
    @PostMapping("/paper/{paperId}/student/{answerSheetId}/base")
    @PreAuthorize("@permissionValidator.isStudent()")
    public Result saveAnswerSheet(
            @PathVariable("paperId") Long paperId,
            @PathVariable("answerSheetId") Long answerSheetId,
            @RequestBody List<AnswerSheetTypeDTO> answerSheetTypeList) {
        answerSheetService.save(answerSheetId, answerSheetTypeList, paperId);
        return Result.success();
    }

    @ApiOperation("考试：理论题交卷")
    @PutMapping("/paper/{paperId}/student/{answerSheetId}/base")
    @PreAuthorize("@permissionValidator.isStudent()")
    public Result<Integer> submitAnswerSheet(
            @PathVariable("paperId") Long paperId,
            @PathVariable("answerSheetId") Long answerSheetId,
            @RequestBody List<AnswerSheetTypeDTO> answerSheetTypeList) {
        return Result.success(answerSheetService.submitBase(answerSheetId, answerSheetTypeList, paperId));
    }

    @ApiOperation("考试：实验题交卷")
    @PostMapping("/paper/{paperId}/student/{answerSheetId}/report")
    @PreAuthorize("@permissionValidator.isStudent()")
    public Result submitAnswerSheet(@PathVariable("paperId") Long paperId, @PathVariable("answerSheetId") Long answerSheetId) {
        answerSheetService.submitExperiment(answerSheetId, paperId);
        return Result.success();
    }

    @ApiOperation("考试：上传实验报告")
    @PostMapping("/paper/{paperId}/student/{answerSheetId}/report/{questionId}")
    @PreAcquireLock(value = ReportConstant.UPDATE_PAPER_EXPERIMENT_REPORT)
    public Result<String> uploadReport(
            @PathVariable("answerSheetId") Long answerSheetId,
            @PathVariable("questionId") Long questionId,
            @RequestParam("file") MultipartFile file
    ) {
        return Result.success(experimentService.uploadTestReport(answerSheetId, questionId, file, userInfoHolder.getUser().getName()));
    }

    @ApiOperation("考试：保存在线实验报告")
    @PutMapping("/paper/{paperId}/student/{answerSheetId}/report/{questionId}")
    public Result<ExperimentReportDTO> saveReport(
            @PathVariable("questionId") Long questionId,
            @PathVariable("answerSheetId") Long answerSheetId,
            @RequestBody @Valid ReportParam param) {
        experimentService.saveTestReport(answerSheetId, questionId, param);
        return Result.success();
    }

    @ApiOperation("批阅：获取学生答题列表")
    @GetMapping("/paper/{paperId}/student")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<PageDTO<AnswerSheetListDTO>> studentList(
            @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,
            @RequestParam(value = "userInfo", required = false) String userInfo,
            @PathVariable("paperId") Long paperId) {
        return Result.success(paperService.studentList(pageNum, pageSize, userInfo, paperId));
    }

    @ApiOperation("学生答题情况导出")
    @PostMapping("/paper/{paperId}/student/export")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<String> studentExport(@RequestBody StudentExcelDataParam sudentExcelDataParam,
                              @PathVariable("paperId") Long paperId){
        String userInfo = sudentExcelDataParam.getUserInfo();
    	String path = paperService.download(userInfo, paperId);
    	return Result.success(path);
    }

    @ApiOperation("批阅：学生答题情况下载")
    @GetMapping("/paper/{paperId}/student/download")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<String> downloadPdfZip(String userInfo,
                                        @PathVariable("paperId") Long paperId){
        String path = paperService.downloadPdfZip(userInfo, paperId);
        return Result.success(path);
    }

    @ApiOperation("批阅：获取学生答题详情")
    @GetMapping("/paper/{paperId}/student/{answerSheetId}")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result<PaperReadingDTO> studentDetails(@PathVariable("answerSheetId") Long answerSheetId) {
        return Result.success(paperService.studentDetails(answerSheetId));
    }

    @ApiOperation("批阅：提交、修改批阅")
    @PostMapping("/paper/{paperId}/student/{answerSheetId}")
    @PreAuthorize("@permissionValidator.isTeacher()")
    @PreAcquireLock(value = ReportConstant.UPDATE_PAPER_CHECK)
    public Result readPaper(
            @PathVariable("answerSheetId") Long answerSheetId,
            @RequestBody List<TypeReadingDTO> typeReadingList
    ) {
        paperService.readPaper(answerSheetId, typeReadingList);
        return Result.success();
    }

    @ApiOperation("修改查重比率")
    @PostMapping("/paper/{paperId}/duplicate-percent")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result updateDuplicatePercent(@PathVariable("paperId") Long paperId, @RequestBody @Valid DuplicateParam param) {
        CourseTestPaper paper = BeanUtil.transform(CourseTestPaper.class, param);
        paper.setId(paperId);

        paperService.updatePaper(paper);
        return Result.success();
    }

    @ApiOperation("检查题目数量")
    @GetMapping("/paper-model/{modelId}/check")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result checkModel(@PathVariable Long modelId, @PathVariable Long courseId){
        return Result.success(paperModelService.checkModel(modelId, courseId));
    }
    @ApiOperation("考试下载")
    @PostMapping("/paper/student/{paperId}/download")
    @PreAuthorize("@permissionValidator.isTeacher()")
    public Result download(@PathVariable("paperId") Long paperId, @RequestParam(value = "className") String className, @RequestParam(value = "paperName") String paperName) {
        paperService.download(paperId,className,paperName);
        return Result.success();
    }
}
